<!-- 筛选组件 -->
<template lang="pug">
g-h
  div.blank(@click="$emit('close')" :style="blankStyle")
  g-h.filter-button(:style="filterStyle")
    div.reset(@click="reset") 重置
    div.confirm(@click="confirm") 确认

  div.filter(:style="filterStyle")
    g-h.filter-block(v-for="(block, i) in filterData" :key="i" j-c="space-between")
      div.filter-title {{ block.kTitle }}
        span.required(v-if="block.validate && block.validate.required") *
        img.scan(
            v-if="block.scan"
            src="img/scan.svg"
            width="22"
            @click="scan"
            )
      DropDownList.dropdown-list(
          v-if="block.tag === 'dropdown'"
          :list="block.list"
          :curValue="block.vTitle"
          @select="select($event, i)"
          :style="dropdownZIndex(i)"
          )
      input.input-item(
          v-else-if="block.tag === 'input'"
          v-model="block.vTitle"
          )
      mt-switch.switch-item(
          v-else-if="block.tag === 'switch'"
          v-model="block.switchValue"
          )
    div.bottom
      
</template>

<script>
/*
  事件
    close     关闭筛选页面
    reset     点击重置按钮
    confirm   点击确定按钮
*/

// NOTE the order of the filters can't change at runtime
import util from "$util"

export default {
  name: "CascadeFilter",
  props: {
    // 动态地判断是否显示筛选页面
    showFilter: {
      type: Boolean,
      default: false,
    },

    /* 
    筛选配置
      {
        k: "status",            // 传给后台的字段
        kTitle: "状态",         // 显示的标签
        tag: "dropdown",        // 类型: dropdown是下拉，input是输入框，switch是开关
        async getOptionList() { // 请求后台获取下拉数据的函数
          try {
            let data = await api.StockFilterGetReal({
              Plant: PLANT,
            })

            // 返回的数组里的每一个数据都要转化成包含id和name的对象, id是值，name是显示的文字
            let newData = []
            for (let item of data) {
              if (item.ItemValue !== "") {
                newData.push({
                  id: item.ItemValue,
                  name: item.ItemText,
                })
              }
            }

            return newData
          } catch(err) {
            throw err
          }
        },
        list: [{                // 固定的下拉选项列表
          name: "",
        }],
      }

    示例:
      [
        {
          k: "status",
          kTitle: "状态",
          v?: "ok",
          vTitle?: "ok(abc)",
          tag: "dropdown",
          getOptionList() {
          },
          list: [{
            name: "",
          }],
        },
        {
          k: "name",
          kTitle: "商品名",
          v?: "ok",
          vTitle?: "ok",
          tag: "input",
        },
      ]
    */
    filterData: {
      type: Array,
      default: () => [],
    },

    /*
      级联配置
      示例:
      只有选择了StorgelocationCode才能选WmNo，只有选择了WmNo才能选ZoneNo
      [
        ["StorgelocationCode", "WmNo", "ZoneNo"],
        ["ProductionNo"],
      ]
    */
    cascade: {
      type: Array,
      default: () => [],
    },
  },

  data() {
    return {
      startCascadeList: [],
      otherCascadeList: [],
      nextCascadeMap: {},
    }
  },
  computed: {
    blankStyle() {
      let a = {}
      if (this.showFilter){
        a = {
          background: "rgba(0,0,0,0.5)", // NOTE: #00000080 does not work in android
          visibility: "visible",
        }
      } else {
        a = {
          background: "rgba(0,0,0,0)",
          visibility: "hidden",
        }
      }
      return a
    },

    filterStyle() {
      let a = {}
      if (this.showFilter){
        a = {
          transform: "translateX(0%)",
          visibility: "visible",
        }
      } else {
        a = {
          transform: "translateX(100%)",
          visibility: "hidden",
        }
      }
      return a
    },
  },
  watch: {
    showFilter(v) {
      if (v) {
        this.registerScanner()
      }
    },
  },

  methods: {
    init() {
      let indexMap = {}
      for (let i = 0, length = this.filterData.length; i < length; i++) {
        let item = this.filterData[i]
        indexMap[item.k] = i
      }

      let startCascadeList = []
      let otherCascadeList = []
      let allCascadeList = []
      for (let subList of this.cascade) {
        let subAllList = []
        for (let i = 0, length = subList.length; i < length; i++) {
          let index = indexMap[subList[i]]
          subAllList.push(index)
          if (i === 0) {
            startCascadeList.push(index)
          } else {
            otherCascadeList.push(index)
          }
        }
        allCascadeList.push(subAllList)
      }

      this.startCascadeList = startCascadeList
      this.otherCascadeList = otherCascadeList

      /* {
        1: {
          list: [2, 3],
          next: 5,
        },
      } */
      let m = {}
      for (let subList of allCascadeList) {
        for (let i = 0, length = subList.length; i < length; i++) {
          let list = subList
          let next = -1
          if (i < length - 1) {
            list = subList.slice(0, i + 1)
            next = subList[i + 1]
          }
          m[subList[i]] = {
            list,
            next,
          }
        }
      }
      this.nextCascadeMap = m
    },

    getStartCascade() {
      for (let i of this.startCascadeList) {
        this.getList(i)
      }
    },

    reset() {
      for (let block of this.filterData) {
        block.v = ""
        block.vTitle = ""
        if (block.tag === "switch") {
          block.switchValue = false
        }
      }
      for (let i of this.startCascadeList) {
        this.$set(this.filterData, i, this.filterData[i])
      }
      for (let i of this.otherCascadeList) {
        this.filterData[i].list = null
        this.$set(this.filterData, i, this.filterData[i])
      }
      this.$emit("reset")
    },

    select(option, i) {
      this.filterData[i].v = option.v
      this.filterData[i].vTitle = option.vTitle
      this.$set(this.filterData, i, this.filterData[i])

      let next = this.nextCascadeMap[i]
      if (!next) {
        return
      }

      let req = {}
      for (let i = 0; i < next.list.length; i++) {
        let block = this.filterData[next.list[i]]
        req[block.k] = block.v
      }

      this.getList(next.next, req)
    },

    async getList(i, req) {
      if (i < 0) {
        return
      }
      try {
        let block = this.filterData[i]
        let list = await block.getOptionList(req)
        block.v = ""
        block.vTitle = ""
        block.list = list
        // NOTE only this can trigger vue's reactivity system
        this.$set(this.filterData, i, block)
      } catch(err) {
        this.$root.error(err)
      }
    },

    validate() {
      for (let block of this.filterData) {
        let validate = block.validate
        if (!validate) {
          continue
        }
        let hasError = false

        if (validate.required) {
          switch (block.tag) {
            case "input":
            case "dropdown":
              if (!block.vTitle) {
                hasError = true
              }
              break
          }
          if (hasError) {
            return `${block.kTitle}没填`
          }
        }
      }
      return ""
    },

    confirm() {
      let msg = this.validate()
      if (msg) {
        util.Alert(msg)
        return
      }

      let selected = []
      for (let block of this.filterData) {
        if (block.tag === "input") {
          if (block.vTitle != undefined) {
            selected.push({
              key: block.k,
              value: block.vTitle,
            })
          }
        } else if (block.tag === "switch") {
          selected.push({
            key: block.k,
            value: block.switchValue,
          })
        } else if (block.v != undefined && block.v !== "") {
          selected.push({
            key: block.k,
            value: block.v,
          })
        }
      }

      this.$emit("confirm", selected)
      this.$emit("close")
    },

    dropdownZIndex(i) {
      return {
        zIndex: 20 - i,
      }
    },

    setScanValue(data) {
      let i = 0
      for (let block of this.filterData) {
        if (block.scan) {
          block.vTitle = data
          this.$set(this.filterData, i, block)
          break
        }
        i++
      }
    },

    scan() {
      let onSuccess = (result) => {
        this.setScanValue(result.text)
      }

      let onError = (error) => {
        console.log("scan failed: ${error}")
      }

      let option = {
        disableSuccessBeep: true,
      }

      cordova.plugins.barcodeScanner.scan(onSuccess, onError, option)
    },

    registerScanner() {
      util.registerScanner((data) => {
        this.setScanValue(data)
      })
    },

  },

  created() {
    this.init()
    this.getStartCascade()
  },
}
</script>

<style lang="stylus" scoped>

.blank
.filter
  z-index: 98
  position: fixed
  top: 0
  bottom: 0
  transition: all 300ms

.bottom
  height: 1rem

.filter-button
  z-index: 99 
  position: fixed
  bottom: 0
  right: 0
  width: 80%
  transition: all 300ms

// 左侧的空白
.blank
  width: 100%
  touch-action: none

// 右侧的筛选
.filter
  right: 0
  width: 80%
  padding: 2rem 1rem
  box-shadow: 0 0 10px grey400
  background: grey100
  overflow-no-scrollbar()

.reset
.confirm
  width: 50%
  font-size: 20px
  padding: 0.7rem
  text-align: center

// 重置按钮
.reset
  background: grey300
  color: grey700
  &:active
    background: grey500
    color: grey200

// 确认按钮
.confirm
  background: red500
  color: white
  &:active
    background: grey300
    color: red500

.filter-block
  position: relative
  margin-bottom: 1rem

.filter-title
  font-size: 18px
  margin-bottom: 0.5em
  color: grey700
  &> .scan
    margin-left: 0.5rem
    margin-bottom: 0.2rem

.filter-item
  font-size: 14px
  margin: 0.3rem 0.3rem
  width: 29%
  height: 2.5em
  padding: 0.4rem
  border-radius: 5px
  background: grey300
  text-ellipsis()

  &-selected
    color: red500
    background: grey100
    border: 1px solid red500

.dropdown-list
  position: absolute
  right: 0.5rem
  width: 60%

.input-item
  position: absolute
  right: 0.5rem
  width: 60%
  border: 1px solid grey500
  border-radius: 0.3rem
  padding: 0.3rem

.required
  color: red

</style>
